package cn.com.liuxiaoluxx.cloud.api.config;

import com.google.common.base.Strings;

import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import java.util.LinkedHashMap;
import java.util.Map;

import javax.annotation.Resource;

import cn.com.liuxiaoluxx.cloud.api.config.realm.MySessionManager;
import cn.com.liuxiaoluxx.cloud.api.config.realm.MyShiroRealm;
import cn.com.liuxiaoluxx.cloud.facade.service.user.UserService;

/**
 * The type IntelliJ IDEA.
 * <p>
 *
 * @author liuxiaolu
 * @date 2020/9/18
 */
@Configuration
public class ShiroConfig {

    @Value("${base-redis-host}")
    private String host;

    @Value("${base-redis-port}")
    private int port;

    @Value("${base-redis-timeout}")
    private int timeout;

    @Value("${base-redis-pwd}")
    private String password;

    @Resource
    private UserService userService;

    /**
     * 权限规则配置
     **/
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();

        //swagger资源不拦截
        filterChainDefinitionMap.put("/swagger-ui.html", "anon");
        filterChainDefinitionMap.put("/swagger-resources/**/**", "anon");
        filterChainDefinitionMap.put("/v2/api-docs", "anon");
        filterChainDefinitionMap.put("/webjars/springfox-swagger-ui/**", "anon");
        filterChainDefinitionMap.put("/configuration/security", "anon");
        filterChainDefinitionMap.put("/configuration/ui", "anon");

        filterChainDefinitionMap.put("/users/login", "anon");
        filterChainDefinitionMap.put("/users/logout", "anon");
        filterChainDefinitionMap.put("/**", "authc");

        shiroFilterFactoryBean.setUnauthorizedUrl("/403");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    /**
     * shiro安全管理器（权限验证核心配置）
     **/
    @Bean
    public DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(getRealm());
        securityManager.setSessionManager(sessionManager());
        securityManager.setCacheManager(cacheManager());

        return securityManager;
    }

    /**
     * 会话管理
     **/
    @Bean
    public SessionManager sessionManager() {
        MySessionManager sessionManager = new MySessionManager();
        //取消登陆跳转URL后面的jsessionid参数
        sessionManager.setSessionIdUrlRewritingEnabled(false);
        sessionManager.setSessionDAO(sessionDAO());
        //不过期
        sessionManager.setGlobalSessionTimeout(-1);
        return sessionManager;
    }

    /**
     * 使用的是shiro-redis开源插件 缓存依赖
     **/
    @Bean
    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(host + ":" + port);
        redisManager.setTimeout(timeout);

        if (!Strings.isNullOrEmpty(password)) {
            redisManager.setPassword(password);
        }
        return redisManager;
    }

    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public static DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        creator.setProxyTargetClass(true);
        return creator;
    }

    /**
     * 使用的是shiro-redis开源插件 session持久化
     **/
    public RedisSessionDAO sessionDAO() {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        return redisSessionDAO;
    }

    /**
     * 缓存管理
     **/
    @Bean
    public CacheManager cacheManager() {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        return redisCacheManager;
    }

    /**
     * 权限管理, 手动注入dubbo服务
     */
    @Bean
    public MyShiroRealm getRealm() {
        return new MyShiroRealm(userService);
    }
}
